package com.hqbzl.chat.utils;

import com.hqbzl.chat.RpcClientManager;
import com.hqbzl.chat.RpcClientManagerEx;
import com.hqbzl.chat.annotations.RpcClientService;
import com.hqbzl.chat.annotations.RpcServerService;
import com.hqbzl.chat.constant.Constants;
import com.hqbzl.chat.message.RpcRequestMessage;
import io.netty.channel.Channel;
import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.concurrent.Promise;
import lombok.extern.slf4j.Slf4j;
import org.reflections.Reflections;
import org.reflections.scanners.FieldAnnotationsScanner;
import org.reflections.scanners.MemberUsageScanner;
import org.reflections.scanners.MethodAnnotationsScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
public class Helper {
    static AtomicInteger SEQUENCEIDGEN = new AtomicInteger();

    static final ConcurrentHashMap<Class, Class> SERVICE_IMAL_MAP = new ConcurrentHashMap<>();
    public static final String COM_HQBZL_CHAT_SERVICE = "com.hqbzl.chat.service";

    public static void initScan() {
        // 实例化Reflections，并指定要扫描的包名
        Reflections reflections = new Reflections(COM_HQBZL_CHAT_SERVICE);
        // 获取包含某个注解的所有类
        Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(RpcServerService.class);
        for (Class<?> aClass : annotated) {
            final Class<?>[] interfaces = aClass.getInterfaces();
            if (interfaces.length == 1) {
                SERVICE_IMAL_MAP.put(interfaces[0], aClass);
            }
        }
    }

    public static Class getImplSerice(Class clazz) {
        final Class targetService = SERVICE_IMAL_MAP.get(clazz);
        if (targetService == null) {
            throw new IllegalStateException("no target ");
        }
        return targetService;
    }

    public static void main1(String[] args) {
        initScan();
        SERVICE_IMAL_MAP.forEach((k, v) -> {
            System.out.println(k + "\t" + v);
        });

//        Reflections reflections = new Reflections(new ConfigurationBuilder().setUrls(ClasspathHelper.forPackage(COM_HQBZL_CHAT_SERVICE)).setScanners(new MethodAnnotationsScanner()));
//        Reflections reflections = new Reflections(new ConfigurationBuilder().forPackages(COM_HQBZL_CHAT_SERVICE).addScanners(new FieldAnnotationsScanner()));
        Reflections reflections = new Reflections(new ConfigurationBuilder().forPackages(COM_HQBZL_CHAT_SERVICE).addScanners(new MemberUsageScanner()));
        final Set<Field> fieldsAnnotatedWith = reflections.getFieldsAnnotatedWith(RpcClientService.class);
        System.out.println("============================================");
        for (Field field : fieldsAnnotatedWith) {
            System.out.println("field = " + field);
        }
        System.out.println("============================================");
        //        Reflections reflections = new Reflections(new ConfigurationBuilder().forPackages(COM_HQBZL_CHAT_SERVICE).addScanners(new MethodAnnotationsScanner()));
//        Set<Method> methods = reflections.getMethodsAnnotatedWith(RpcClientService.class);
//        for (Method method : methods) {
//            System.out.println("method = " + method);
//        }
    }

    public static void main2(String[] args) {
        final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder().forPackages(COM_HQBZL_CHAT_SERVICE).addScanners(new FieldAnnotationsScanner()).filterInputsBy(x -> {
//            System.out.println("filterInputsBy = " + x);
            return x.startsWith("com/hqbzl/chat/");
        });
        Reflections reflections = new Reflections(configurationBuilder);
        final Set<Field> fieldsAnnotatedWith = reflections.getFieldsAnnotatedWith(RpcClientService.class);
        System.out.println("============================================");
        for (Field field : fieldsAnnotatedWith) {
            final Class<?> type = field.getType();
            final String name = field.getName();
            System.out.println(type + "\t" + name);
            final Constructor<?>[] declaredConstructors = type.getDeclaredConstructors();
            final Method[] declaredMethods = type.getDeclaredMethods();
            System.out.println("declaredMethods = " + declaredMethods.length);
//            System.out.println("field = " + field);
        }
    }

    public static void main(String[] args) {
        RpcClientManagerEx rpc = new RpcClientManagerEx();

    }

    public static void init(RpcClientManagerEx rpc) {
    }

    public static <T> T getProxyService(Class<T> serviceClass) {
        final Channel channel = RpcClientManager.getChannel();
        final ClassLoader classLoader = serviceClass.getClassLoader();
        final Class[] interfaceClass = new Class[]{serviceClass};
        final Object o = Proxy.newProxyInstance(classLoader, interfaceClass, (proxy, method, args) -> {
            final int sequenceId = SEQUENCEIDGEN.incrementAndGet();
            // 1、将方法调用转为消息对象
            final RpcRequestMessage rpc = RpcRequestMessage
                    .builder()
                    .sequenceId(sequenceId)
                    .interfaceName(serviceClass.getName())
                    .methodName(method.getName())
                    .parameterTypes(method.getParameterTypes())
                    .parameterValus(args)
                    .returnType(method.getReturnType())
                    .build();
            // 2、将消息对象发出
            log.debug("getProxyService====================>: {}", rpc.toString());
            // 指定promise对象接收结果的线程
            channel.writeAndFlush(rpc);
            // 3、处理返回值 准备一个promise对象来接收结果， 参数表明接收结果的线程
            DefaultPromise<Object> promise = new DefaultPromise<>(channel.eventLoop());
            Constants.PROMISE_MAP.put(sequenceId, promise);
            // 4、等结果，await不会抛异常
            final Promise<?> await = promise.await();
            if (await.isSuccess()) {
                // 有结果正常响应
                return promise.getNow();
            } else {
                throw new RuntimeException(promise.cause());
            }
        });
        return (T) o;
    }
}
